package com.hh.core.config;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.codec.Base64;
import org.apache.shiro.session.SessionListener;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.Cookie;
import org.apache.shiro.web.servlet.ShiroHttpSession;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.config.MethodInvokingFactoryBean;
import org.springframework.cache.ehcache.EhCacheManagerFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;

import com.hh.core.listener.LoginSessionListener;
import com.hh.core.property.ShiroProperty;
import com.hh.core.shiro.ShiroUserRealm;

/**
 *
 * @ClassName: ShiroConfig
 * @Description: TODO(shiro权限管理的配置)
 * @author hxn
 * @date 2018年1月15日 上午10:34:58
 *
 */
@Configuration
public class ShiroConfig {

	/**
	 * 
	 * @Title: shiroFilter
	 * @Description: Shiro的过滤器链
	 * @param @param securityManager
	 * @param @return 设定文件
	 * @return ShiroFilterFactoryBean 返回类型
	 * @author hxn
	 * @date 2018年1月15日 下午3:11:15
	 * @throws
	 */
	@Bean
	public ShiroFilterFactoryBean shiroFilter(
			DefaultWebSecurityManager securityManager,ShiroProperty shiroProperty) {
		ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
		shiroFilter.setSecurityManager(securityManager);

		// 默认的登陆访问url
		shiroFilter.setLoginUrl(shiroProperty.getLoginUrl());
		// 登陆成功后跳转的url
		shiroFilter.setSuccessUrl(shiroProperty.getSuccessUrl());
		// 没有权限跳转的url
		shiroFilter.setUnauthorizedUrl(shiroProperty.getUnauthorizedUrl());
		/**
		 * 配置shiro拦截器链
		 *
		 * anon 不需要认证 authc 需要认证 user 验证通过或RememberMe登录的都可以
		 *
		 */
		Map<String, String> hashMap = new LinkedHashMap<>();
		String[] anonUrl = shiroProperty.getAnonUrl().split(",");
		for (String str : anonUrl) {
			hashMap.put(str, "anon");
		}
		String[] authcUrl = shiroProperty.getAuthcUrl().split(",");
		for (String str : authcUrl) {
			hashMap.put(str, "user");
		}
		return shiroFilter;
	}

	/**
	 * 
	 * @Title: securityManager
	 * @Description: 安全管理器配置
	 * @param @param rememberMeManager
	 * @param @param cacheShiroManager
	 * @param @param sessionManager
	 * @param @return 设定文件
	 * @return DefaultWebSecurityManager 返回类型
	 * @author hxn
	 * @date 2018年1月15日 上午10:36:00
	 * @throws
	 */
	@Bean
	public DefaultWebSecurityManager securityManager(
			CookieRememberMeManager rememberMeManager,
			CacheManager cacheShiroManager, SessionManager sessionManager) {
		DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
		securityManager.setRealm(this.shiroUserRealm()); // 自定义 Realm
		securityManager.setCacheManager(cacheShiroManager); // 缓存管理
		securityManager.setRememberMeManager(rememberMeManager);// 记住管理
		securityManager.setSessionManager(sessionManager); // Session
		return securityManager;
	}

	/**
	 * 
	 * @Title: defaultWebSessionManager
	 * @Description: shiro session管理器
	 * @param @param cacheShiroManager
	 * @param @param baseProperty
	 * @param @return 设定文件
	 * @return DefaultWebSessionManager 返回类型
	 * @author hxn
	 * @date 2018年1月15日 上午10:44:02
	 * @throws
	 */
	@Bean
	public DefaultWebSessionManager defaultWebSessionManager(
			CacheManager cacheShiroManager,ShiroProperty shiroProperty) {
		DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
		List<SessionListener> listeners = new ArrayList<>();
		listeners.add(new LoginSessionListener());
		sessionManager.setSessionListeners(listeners);
		sessionManager.setCacheManager(cacheShiroManager);
		sessionManager.setSessionValidationInterval(shiroProperty
				.getSessionValidationInterval() * 1000); // 检测一次失效的session时间
		sessionManager.setGlobalSessionTimeout(shiroProperty
				.getSessionInvalidateTime() * 1000); // 全局的session会话超时时间
		sessionManager.setDeleteInvalidSessions(true);  //删除所有无效的Session对象
		sessionManager.setSessionValidationSchedulerEnabled(true);  //无效的Session定时调度器
		Cookie cookie = new SimpleCookie(
				ShiroHttpSession.DEFAULT_SESSION_ID_NAME);
		cookie.setName("shiroCookie");
		cookie.setHttpOnly(true);
		sessionManager.setSessionIdCookie(cookie);
		return sessionManager;
	}

	/**
	 * 
	 * @Title: getCacheShiroManager
	 * @Description: 缓存管理器 使用Ehcache实现
	 * @param @param ehcache
	 * @param @return 设定文件
	 * @return CacheManager 返回类型
	 * @author hxn
	 * @date 2018年1月15日 上午10:44:22
	 * @throws
	 */
	@Bean
	public CacheManager getCacheShiroManager(EhCacheManagerFactoryBean ehcache) {
		EhCacheManager ehCacheManager = new EhCacheManager();
		ehCacheManager.setCacheManager(ehcache.getObject());
		return ehCacheManager;
	}

	/**
	 * 项目自定义的Realm
	 */
	@Bean
	public ShiroUserRealm shiroUserRealm() {
		return new ShiroUserRealm();
	}

	/**
	 * 
	 * @Title: rememberMeManager
	 * @Description: rememberMe管理器, cipherKey生成见采用的是AES加密
	 * @param @param rememberMeCookie
	 * @param @return 设定文件
	 * @return CookieRememberMeManager 返回类型
	 * @author hxn
	 * @date 2018年1月15日 下午3:12:03
	 * @throws
	 */
	@Bean
	public CookieRememberMeManager rememberMeManager(
			SimpleCookie rememberMeCookie) {
		CookieRememberMeManager manager = new CookieRememberMeManager();
		manager.setCipherKey(Base64.decode("aGhhZG1pbgAAAAAAAAAAAA===="));
		manager.setCookie(rememberMeCookie);
		return manager;
	}

	/**
	 * 
	 * @Title: rememberMeCookie
	 * @Description: 记住密码Cookie
	 * @param @return 设定文件
	 * @return SimpleCookie 返回类型
	 * @author hxn
	 * @date 2018年1月15日 下午3:12:11
	 * @throws
	 */
	@Bean
	public SimpleCookie rememberMeCookie(ShiroProperty shiroProperty) {
		SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
		simpleCookie.setHttpOnly(true);
		simpleCookie.setMaxAge(shiroProperty.getRememberMeDays());// 7天
		return simpleCookie;
	}

	/**
	 * 
	 * @Title: methodInvokingFactoryBean
	 * @Description: 在方法中 注入 securityManager,进行代理控制
	 * @param @param securityManager
	 * @param @return 设定文件
	 * @return MethodInvokingFactoryBean 返回类型
	 * @author hxn
	 * @date 2018年1月15日 下午3:15:27
	 * @throws
	 */
	@Bean
	public MethodInvokingFactoryBean methodInvokingFactoryBean(
			DefaultWebSecurityManager securityManager) {
		MethodInvokingFactoryBean bean = new MethodInvokingFactoryBean();
		bean.setStaticMethod("org.apache.shiro.SecurityUtils.setSecurityManager");
		bean.setArguments(new Object[] { securityManager });
		return bean;
	}

	/**
	 * 
	 * @Title: lifecycleBeanPostProcessor
	 * @Description: 保证实现了Shiro内部lifecycle函数的bean执行
	 * @param @return 设定文件
	 * @return LifecycleBeanPostProcessor 返回类型
	 * @author hxn
	 * @date 2018年1月15日 下午3:15:46
	 * @throws
	 */
	@Bean
	public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
		return new LifecycleBeanPostProcessor();
	}

	/**
	 * 
	 * @Title: defaultAdvisorAutoProxyCreator
	 * @Description: 启用shrio授权注解拦截方式，AOP式方法级权限检查
	 * @param @return 设定文件
	 * @return DefaultAdvisorAutoProxyCreator 返回类型
	 * @author hxn
	 * @date 2018年1月15日 下午3:16:11
	 * @throws
	 */
	@Bean
	@DependsOn(value = "lifecycleBeanPostProcessor")
	// 依赖其他bean的初始化
	public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
		return new DefaultAdvisorAutoProxyCreator();
	}

	/**
	 * 
	 * @Title: authorizationAttributeSourceAdvisor
	 * @Description: 添加 Shiro Spring AOP 权限注解的支持
	 * @param @param securityManager
	 * @param @return 设定文件
	 * @return AuthorizationAttributeSourceAdvisor 返回类型
	 * @author hxn
	 * @date 2018年1月15日 下午3:19:00
	 * @throws
	 */
	@Bean
	public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(
			DefaultWebSecurityManager securityManager) {
		AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
		authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
		return authorizationAttributeSourceAdvisor;
	}

}
